﻿namespace _02.IEnumerableArithmeticFunction
{
    using System;
    using System.Collections.Generic;

    public static class IEnumerableExtension
    {
        public static T Sum<T>(this IEnumerable<T> enumeration)
            where T : IComparable<T>
        {
            if (enumeration == null)
            {
                throw new ArgumentNullException();
            }

            decimal sum = 0;

            try
            {
                foreach (var item in enumeration)
                {
                    sum += Convert.ToDecimal(item);
                }
            }
            catch (FormatException)
            {
                throw new FormatException("The element is non convertable to decimal.");
            }
            catch (OverflowException)
            {
                throw new OverflowException("The element exceed maximal decimal value.");
            }

            return (T)sum;
        }

        public static T Product<T>(this IEnumerable<T> enumeration)
            where T : IComparable<T>
        {
            if (enumeration == null)
            {
                throw new ArgumentNullException();
            }

            decimal product = 0;

            try
            {
                foreach (var item in enumeration)
                {
                    product *= Convert.ToDecimal(item);
                }
            }
            catch (FormatException)
            {
                throw new FormatException("The element is non convertable to decimal.");
            }
            catch (OverflowException)
            {
                throw new OverflowException("The element exceed maximal decimal value.");
            }

            return (T)product;
        }

        public static T Min<T>(this IEnumerable<T> enumeration)
            where T : IComparable<T>
        {
            if (enumeration == null)
            {
                throw new ArgumentNullException();
            }

            T min = enumeration.First();
            foreach (var item in enumeration)
            {
                if (item.CompareTo(min) < 0)
                {
                    min = item;
                }
            }

            return min;
        }

        public static T Max<T>(this IEnumerable<T> enumeration)
            where T : IComparable<T>
        {
            if (enumeration == null)
            {
                throw new ArgumentNullException();
            }

            T max = enumeration.First();
            foreach (var item in enumeration)
            {
                if (item.CompareTo(max) > 0)
                {
                    max = item;
                }
            }

            return max;
        }

        public static T Average<T>(this IEnumerable<T> enumeration)
            where T : IComparable<T>
        {
            return (dynamic)enumeration.Sum<T>() / enumeration.Count();
        }

        public static T First<T>(this IEnumerable<T> collection)
        {
            foreach (var item in collection)
            {
                return item;
            }

            return default(T);
        }

        static long Count<T>(this IEnumerable<T> collection)
        {
            long count = 0;
            foreach (var item in collection)
            {
                count++;
            }

            return count;
        }
    }
}
